//:C16:AutoCounter.h
#ifndef AUTOCOUNTER_H__
#define AUTOCOUNTER_H__
#include "../require.h"
#include <iostream>
#include <set>    // Standard C++ Library container
#include <string>

class AutoCounter
{
    static int count;
    int id;
    class CleanupCheck
    {
        std::set<AutoCounter*> trace;
        public:
            void add(AutoCounter *ap)
            {
                trace.insert(ap);
            }
            void remove(AutoCounter *ap)
            {
                require(trace.erase(ap) == 1,
                        "Attempt to delete AutoCounter twice");
            }
            ~CleanupCheck()
            {
                std::cout << "~CleanupCheck()" << std::endl;
                require(trace.size() == 0,
                        "All AutoCounter objects not cleaned up");
            }
    };
    static CleanupCheck verifier;
    AutoCounter() : id(count++)
    {
        verifier.add(this);    // Register itself
        std::cout << "created[" << id << "]"
            << std::endl;                               
    }
    // Prevent assignment and copy-construction:
    AutoCounter(const AutoCounter &);
    void operator=(const AutoCounter &);
    public:
        // You can only create object with this:
        static AutoCounter *create()
        {
            return new AutoCounter();
        }
        ~AutoCounter()
        {
            std::cout << "destroying[" << id
                     << "]" << std::endl;
            verifier.remove(this);    
        }
        // Print both objects and pointes:
        friend std::ostream &
            operator<<(std::ostream &os, const AutoCounter &ac)
            {
                return os << "AutoCounter " << ac.id;
            }
        friend std::ostream & 
            operator<<(std::ostream &os, const AutoCounter *ac)
            {
                return os << "AutoCounter " << ac->id;
            }
};
#endif
